using System;
using System.IO;
using System.Reflection;
using System.Collections;

using GURUCORE.Framework.Core.Util.Localization;
using log4net;

namespace GURUCORE.Framework.Core
{
	/// <summary>
	/// GApplication
    /// Description : abstract class for all GURUCORE centric application
    /// Author : DuongNA - Modified by LockeVN
	/// </summary>
	public abstract class GApplication
	{
        public const string CONFIG_FILENAME = "Config.config";

		/// <summary>
		/// lock object
		/// </summary>
		private static object m_oLockInstance = new object();
		private static object m_oLockSharedObjects = new object();

		private string m_sRootDir;
        /// <summary>
        /// Physical Directory path to the  Root of this website application. having the last backslash
        /// </summary>
		public string RootDir
		{
			get { return m_sRootDir; }
			set { m_sRootDir = value; }
        }

        



        #region Singleton
        

        /// <summary>
		/// private constructor for singleton implementation
		/// </summary>
		protected GApplication()
		{
			m_htSharedObjects = new Hashtable();
		}
        /// <summary>
        /// global single instance of GApplication implementation
        /// </summary>
        private static GApplication m_oInstance;
        /// <summary>
        /// get singleton instance
        /// </summary>
        /// <returns></returns>
        public static GApplication GetInstance()
        {
            int nURIOffset = "file:///".Length;
            if (null == m_oInstance)
            {
                AppConfiguration oCfg;
                lock (m_oLockInstance)
                {
                    //load application config
                    string sCodeBase = Assembly.GetExecutingAssembly().CodeBase;
                    FileInfo oCodeBaseFile = new FileInfo(sCodeBase.Substring(nURIOffset, sCodeBase.Length - nURIOffset));
                    string sConfigFilePath;

                    //find config file in assembly directory
                    DirectoryInfo oBinDir = new DirectoryInfo(oCodeBaseFile.Directory.FullName);
                    DirectoryInfo oConfigDir = new DirectoryInfo(oCodeBaseFile.Directory.FullName + "/Config/System/");
                    if (oConfigDir.Exists && (oConfigDir.GetFiles(CONFIG_FILENAME).Length > 0))
                    {
                    }
                    else
                    {
                        //find config file in assembly directory 's parent
                        oConfigDir = new DirectoryInfo(oCodeBaseFile.Directory.Parent.FullName + "/Config/System/");
                        if (oConfigDir.Exists && (oConfigDir.GetFiles(CONFIG_FILENAME).Length > 0))
                        {
                        }
                        else
                        {
                            //find config file in assembly directory 's parent 's parent
                            oConfigDir = new DirectoryInfo(oCodeBaseFile.Directory.Parent.Parent.FullName + "/Config/System/");
                            if (oConfigDir.Exists && (oConfigDir.GetFiles(CONFIG_FILENAME).Length > 0))
                            {

                            }
                            else
                            {
                                //find config file in working directory
                                oConfigDir = new DirectoryInfo("./Config/System/");
                                if (oConfigDir.Exists && (oConfigDir.GetFiles(CONFIG_FILENAME).Length > 0))
                                {

                                }
                                else
                                {
                                    throw new Exception("GURUCORE Framework error: could not find application config file while load the first instance of GApplication");
                                }
                            }
                        }
                    }

                    // PERFORMANCE: Lockevn     sConfigFilePath = oConfigDir.GetFiles(CONFIG_FILENAME)[0].FullName;
                    sConfigFilePath = oConfigDir.FullName + CONFIG_FILENAME;
                    oCfg = new AppConfiguration(sConfigFilePath);

                    string sApplicationClass = oCfg.ApplicationClass;
                    string sApplicationAssembly = oBinDir.GetFiles(oCfg.ApplicationAssembly)[0].FullName;

                    Assembly oAsm;
                    if (string.IsNullOrEmpty(sApplicationAssembly))
                    {
                        oAsm = Assembly.GetCallingAssembly();
                    }
                    else
                    {
                        oAsm = Assembly.LoadFrom(sApplicationAssembly);
                    }
                    Type tApplicationClass = oAsm.GetType(sApplicationClass);

                    //create instance
                    m_oInstance = (GApplication)Activator.CreateInstance(tApplicationClass, true);

                    m_oInstance.AddSharedObject(AppConfiguration.GLOBAL_CACHE_KEY, oCfg);

                    if (Convert.ToBoolean(oCfg.AutoStart))
                    {
                        m_oInstance.Start(oCfg.AutoStartParam);
                    }
                }
            }
            return m_oInstance;
        }


        /// <summary>
        /// shared objects hashtable
        /// </summary>
        private Hashtable m_htSharedObjects;
		/// <summary>
		/// add an object for global sharing, threadsafe
		/// </summary>
		/// <param name="p_sName"></param>
		/// <param name="p_oSharedObject"></param>
		public virtual void AddSharedObject(string p_sName, object p_oSharedObject)
		{
			lock (m_oLockSharedObjects)
			{
                if (!m_htSharedObjects.Contains(p_sName))
                {
                    m_htSharedObjects.Add(p_sName, p_oSharedObject);
                }
                    // HACK: Lockevn: allow update cache
                else
                {
                    m_htSharedObjects[p_sName] = p_oSharedObject;
                }
			}
		}

		/// <summary>
		/// get a global shared object
		/// </summary>
		/// <param name="p_sName"></param>
		/// <returns></returns>
		public virtual object GetSharedObject(string p_sName)
		{
			if (m_htSharedObjects.Contains(p_sName))
			{
				return m_htSharedObjects[p_sName];
			}
			else
			{
				return null;
			}
		}
        public virtual T GetSharedObject<T>(string p_sName)
        {
            if (m_htSharedObjects.Contains(p_sName))
            {
                return (T)m_htSharedObjects[p_sName];
            }
            else
            {
                return default(T);
            }
        }

        #endregion


        private static readonly ILog log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);




		/// <summary>
		/// set locale for global application, set to the thead.CurrentThread. culture
		/// </summary>
		/// <param name="p_sLocale"></param>
		public virtual void SetApplicationLocale(string p_sLocale)
		{
			System.Threading.Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo(p_sLocale);
			System.Threading.Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo(p_sLocale);
		}

		/// <summary>
		/// get current application locale
		/// </summary>
		/// <returns></returns>
		public virtual string GetApplicationLocale()
		{
			return System.Threading.Thread.CurrentThread.CurrentCulture.Name;
		}
        
		private void LoadAllLocalizationResource(string p_sRootDir)
		{
			//search within rootdir
			DirectoryInfo oRootDir = new DirectoryInfo(p_sRootDir);

			foreach (DirectoryInfo oSubDir in oRootDir.GetDirectories("*-*",SearchOption.TopDirectoryOnly))
			{
				string sLocale = oSubDir.Name;
				if (sLocale.Length == 5)
				{
					Hashtable htLocalizationRes = ResourceManager.LoadResource(sLocale, p_sRootDir);
					if (htLocalizationRes != null)
					{
						this.AddSharedObject(ResourceManager.GLOBAL_CACHE_KEY + "#" + sLocale, htLocalizationRes);
					}					
				}
			}

            m_sRootDir = p_sRootDir;
		}




		public virtual void SetSecurityContext(object p_oParam, string p_sKey, object p_oValue)
		{
		}

		public virtual GSS.GURUID GetSecurityContext(object p_oParam, string p_sKey)
		{
			return null;
		}





        /// <summary>
        /// start application, must be overriden
        /// </summary>
        public virtual void Start(object p_oParam)
        {
            log.Info("Logging system started at root " + p_oParam);

            string sRoot = (string)p_oParam;
            m_sRootDir = sRoot;
            //load all localization resource
            LoadAllLocalizationResource(sRoot);
		}

        /// <summary>
        /// stop application, must be overriden
        /// </summary>
        public virtual void Stop(object p_oParam)
        {

        }

        /// <summary>
        /// restart application, must be overriden
        /// </summary>
        public virtual void Restart(object p_oParam)
        {
        }

	}
}
